package org.sam.swing.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;

/**
 * 和反射相关的工具类
 * 
 * @author sam
 *
 */
public class ReflectUtil {

	/**
	 * 获取泛型
	 * 
	 * @param cls
	 * @return
	 */
	public static Class<?> getGenericType(Class<?> cls) {
		Type type = cls.getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			if (((ParameterizedType) type).getActualTypeArguments()[0] instanceof Class) {
				return (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0];
			} else {
				return ((ParameterizedType) type).getActualTypeArguments()[0].getClass();
			}
		}
		return null;
	}
	
	/**
	 * 判断类里是否包含某个字段属性字段
	 * @param cls
	 * @param filedName
	 * @return
	 */
	public static boolean contains(Class<?> cls ,String filedName){
		if (cls == null || StringUtils.isEmpty(filedName))
			throw new RuntimeException("cls or fieldName is null");
		
		Field[] fields = cls.getDeclaredFields();
		if (fields == null || fields.length <= 0)
			return false;
		
		for(Field f : fields){
			if (f.getName().equals(filedName))
				return true;
		}
		
		return false;
	}

	/**
	 * 根据实体获取泛型类型
	 * 
	 * @param entity
	 * @return
	 * @throws Exception
	 */
	public static Class<?> getGenericType(Object entity) throws Exception {
		if (entity == null)
			return null;

		return (Class<?>) ((ParameterizedType) entity.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	/**
	 * 执行get method
	 * 
	 * @param entity
	 * @param colName
	 * @return
	 */
	public static Pair<Boolean, Object> invokeGetMethod(Object entity, String colName) {
		if (entity == null)
			return null;

		try {
			// 先判断get函数，没有get函数，执行is函数
			// 先判断get函数，没有get函数，执行is函数
			Method method = null;
			Class<?> cls = entity.getClass();
			try {
				method = cls.getMethod("get" + colName.substring(0, 1).toUpperCase() + colName.substring(1));
			} catch (Exception ex) {
				method = null;
			}

			if (method == null) {
				try{
				method = cls.getMethod("is" + colName.substring(0, 1).toUpperCase() + colName.substring(1));
				} catch(Exception ex){
					method = null;
				}
			}
			if (method != null) {
				return Pair.of(true, method.invoke(entity));
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return Pair.of(false, null);
	}

	/**
	 * 获取set method执行函数
	 * 
	 * @param entity
	 * @param colName
	 * @return
	 */
	public static Method getMethod(Object entity, String colName) {
		if (entity == null)
			return null;

		try {
			Method method = null;
			Class<?> cls = entity.getClass();
			// 先判断get函数，没有get函数，执行is函数
			try {
				method = cls.getMethod("get" + colName.substring(0, 1).toUpperCase() + colName.substring(1));
			} catch (Exception ex) {
				method = null;
			}

			if (method == null) {
				method = cls.getMethod("is" + colName.substring(0, 1).toUpperCase() + colName.substring(1));
			}

			return method;

		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return null;
	}

	/**
	 * 获取set method执行函数
	 * 
	 * @param entity
	 * @param colName
	 * @return
	 */
	public static Method getSetMethod(Object entity, String colName) {
		if (entity == null)
			return null;

		try {
			Method method = null;
			Class<?> cls = entity.getClass();
			// 先判断get函数，没有get函数，执行is函数
			try {
				method = cls.getMethod("get" + colName.substring(0, 1).toUpperCase() + colName.substring(1));
			} catch (Exception ex) {
				method = null;
			}

			if (method == null) {
				method = cls.getMethod("is" + colName.substring(0, 1).toUpperCase() + colName.substring(1));
			}

			return cls.getMethod("set" + colName.substring(0, 1).toUpperCase() + colName.substring(1),
					method.getReturnType());

		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return null;
	}

	/**
	 * 获取实体上
	 * 
	 * @param entity
	 * @param fieldName
	 * @return
	 */
	public static String getDisplay(Object entity, String fieldName) {
		if (entity == null)
			return "";

		if (StringUtils.isEmpty(fieldName))
			return "";

		try {
			// 带有嵌套效果的对象数据
			if (fieldName.indexOf('.') >= 0) {

				String[] objs = fieldName.split("\\.");
				Object object = entity;

				for (int i = 0; i < objs.length; i++) {

					Method method = getMethod(object, objs[i]);
					if (method != null) {
						object = method.invoke(object);
					} else {
						Field field = object.getClass().getDeclaredField(objs[i]);
						field.setAccessible(true);
						object = field.get(object);
					}
				}

				return object == null ? "" : object.toString();

			} else {

				Method method = getMethod(entity, fieldName);
				Object object = entity;
				if (method != null) {
					object = method.invoke(object);
				} else {
					Field field = entity.getClass().getDeclaredField(fieldName);
					field.setAccessible(true);
					object = field.get(entity);
				}
				return object == null ? "" : object.toString();
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return "";
	}

	/**
	 * 基础数据类型名称
	 */
	private static String[] baseType = new String[] { "int", "short", "long", "byte", "boolean", "float", "double",
			"char" };

	/**
	 * 包装类型名称,包括扩展类型
	 */
	private static String[] packageType = new String[] { "java.lang.Integer", "java.lang.Short", "java.lang.Long",
			"java.lang.Byte", "java.lang.Boolean", "java.lang.Float", "java.lang.Double", "java.lang.Character",
			"java.lang.String" };

	/**
	 * 数值类型列表
	 */
	private static String[] numberType = new String[] { "int", "short", "long", "byte", "float", "double",
			"java.lang.Integer", "java.lang.Short", "java.lang.Long", "java.lang.Byte", "java.lang.Float",
			"java.lang.Double" };

	/**
	 * 判断字段是否是基础类型
	 * 
	 * @param field
	 *            字段类型
	 * @return true : 8 个基础类型(包括包装类) + String
	 */
	public static boolean isBaseType(Field field) throws Exception {
		Type type = field.getGenericType();
		String typeName = type.getTypeName();

		if (ArrayUtils.contains(baseType, typeName))
			return true;

		if (ArrayUtils.contains(packageType, typeName))
			return true;

		return false;
	}

	/**
	 * 是否是数值类型
	 * 
	 * @param field
	 * @throws Exception
	 */
	public static boolean isNumberType(Field field) throws Exception {

		Type type = field.getGenericType();
		String typeName = type.getTypeName();

		if (ArrayUtils.contains(numberType, typeName))
			return true;

		return false;
	}

}
